package org.onvivals.common.param;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.annotation.TableField;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.OrderItem;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.extern.slf4j.Slf4j;
import org.onvivals.common.annotation.QueryField;
import org.onvivals.common.annotation.QueryType;

import java.lang.reflect.Field;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 分页、排序、搜索参数封装
 *
 * @author weirdor (179946422@qq.com)
 * @version v1.0.0
 */
@Slf4j
public class PageParam<T, U extends BaseParam> extends Page<T> {
	private static final long serialVersionUID = 1L;

	/**
	 * 查询条件
	 */
	private final U where;

	/**
	 * 是否把字段名称驼峰转下划线
	 */
	private final boolean isToUnderlineCase;

	public PageParam() {
		this(null);
	}

	public PageParam(U where) {
		this(where, true);
	}

	public PageParam(U where, boolean isToUnderlineCase) {
		super();
		this.where = where;
		this.isToUnderlineCase = isToUnderlineCase;
		if (where != null) {
			// 获取分页页码
			if (where.getPage() != null) {
				setCurrent(where.getPage());
			}
			// 获取分页每页数量
			if (where.getLimit() != null) {
				setSize(where.getLimit());
			}
			// 获取排序方式
			if (where.getSort() != null) {
				if (sortIsSQL(where.getSort())) {
					setOrders(parseOrderSQL(where.getSort()));
				} else {
					List<OrderItem> orderItems = new ArrayList<>();
					String column = this.isToUnderlineCase ? StrUtil.toUnderlineCase(where.getSort()) : where.getSort();
					boolean asc = !"desc".equals(where.getOrder());
					OrderItem orderItem = new OrderItem();
					orderItem.setAsc(asc);
					orderItem.setColumn(column);
					orderItems.add(orderItem);
					setOrders(orderItems);
				}
			}
		}
	}

	/**
	 * 排序字段是否是sql
	 */
	private boolean sortIsSQL(String sort) {
		return sort != null && (sort.contains(",") || sort.trim().contains(" "));
	}

	/**
	 * 解析排序sql
	 */
	private List<OrderItem> parseOrderSQL(String orderSQL) {
		List<OrderItem> orders = new ArrayList<>();
		if (StrUtil.isNotBlank(orderSQL)) {
			for (String item : orderSQL.split(",")) {
				String[] temp = item.trim().split(" ");
				if (!temp[0].isEmpty()) {
					String column = this.isToUnderlineCase ? StrUtil.toUnderlineCase(temp[0]) : temp[0];
					boolean asc = temp.length == 1 || !temp[temp.length - 1].equals("desc");
					OrderItem orderItem = new OrderItem();
					orderItem.setAsc(asc);
					orderItem.setColumn(column);
					orders.add(orderItem);
				}
			}
		}
		return orders;
	}

	/**
	 * 设置默认排序方式
	 *
	 * @param orderItems 排序方式
	 * @return PageParam
	 */
	public PageParam<T, U> setDefaultOrder(List<OrderItem> orderItems) {
		if (orders() == null || orders().size() == 0) {
			setOrders(orderItems);
		}
		return this;
	}

	/**
	 * 设置默认排序方式
	 *
	 * @param orderSQL 排序方式
	 * @return PageParam
	 */
	public PageParam<T, U> setDefaultOrder(String orderSQL) {
		setDefaultOrder(parseOrderSQL(orderSQL));
		return this;
	}

	/**
	 * 获取查询条件
	 *
	 * @param excludes 不包含的字段
	 * @return QueryWrapper
	 */
	public QueryWrapper<T> getWrapper(String... excludes) {
		return buildWrapper(null, Arrays.asList(excludes));
	}

	/**
	 * 获取查询条件
	 *
	 * @param columns 只包含的字段
	 * @return QueryWrapper
	 */
	public QueryWrapper<T> getWrapperWith(String... columns) {
		return buildWrapper(Arrays.asList(columns), null);
	}

	/**
	 * 构建QueryWrapper
	 *
	 * @param columns  包含的字段
	 * @param excludes 排除的字段
	 * @return QueryWrapper
	 */
	private QueryWrapper<T> buildWrapper(List<String> columns, List<String> excludes) {
		QueryWrapper<T> queryWrapper = new QueryWrapper<>();
		Map<String, Object> map = BeanUtil.beanToMap(where, false, true);

		try {

			for (String fieldName : map.keySet()) {
				Object fieldValue = map.get(fieldName);
				if (ObjectUtil.isNotEmpty(fieldValue)){
					Field field = ReflectUtil.getField(where.getClass(), fieldName);

					// 过滤不包含的字段
					if (columns != null && !columns.contains(fieldName)) {
						continue;
					}

					// 过滤排除的字段
					if (excludes != null && excludes.contains(fieldName)) {
						continue;
					}

					// 过滤逻辑删除字段
					if (field.getAnnotation(TableLogic.class) != null) {
						continue;
					}

					// 获取注解指定的查询字段及查询方式
					QueryType queryType = QueryType.LIKE;
					QueryField queryField = field.getAnnotation(QueryField.class);
					if (queryField != null) {
						if (StrUtil.isNotEmpty(queryField.value())) {
							fieldName = queryField.value();
						}
						if (queryField.type() != null) {
							queryType = queryField.type();
						}
					} else {
						// 过滤非本表的字段
						TableField tableField = field.getAnnotation(TableField.class);
						if (tableField != null && !tableField.exist()) {
							continue;
						}
					}

					// 字段名驼峰转下划线
					if (this.isToUnderlineCase) {
						fieldName = StrUtil.toUnderlineCase(fieldName);
					}

					//
					switch (queryType) {
						case EQ:
							queryWrapper.eq(fieldName, fieldValue);
							break;
						case NE:
							queryWrapper.ne(fieldName, fieldValue);
							break;
						case GT:
							queryWrapper.gt(fieldName, fieldValue);
							break;
						case GE:
							queryWrapper.ge(fieldName, fieldValue);
							break;
						case LT:
							queryWrapper.lt(fieldName, fieldValue);
							break;
						case LE:
							queryWrapper.le(fieldName, fieldValue);
							break;
						case LIKE:
							queryWrapper.like(fieldName, fieldValue);
							break;
						case NOT_LIKE:
							queryWrapper.notLike(fieldName, fieldValue);
							break;
						case LIKE_LEFT:
							queryWrapper.likeLeft(fieldName, fieldValue);
							break;
						case LIKE_RIGHT:
							queryWrapper.likeRight(fieldName, fieldValue);
							break;
						case IS_NULL:
							queryWrapper.isNull(fieldName);
							break;
						case IS_NOT_NULL:
							queryWrapper.isNotNull(fieldName);
							break;
						case IN:
							queryWrapper.in(fieldName, fieldValue);
							break;
						case NOT_IN:
							queryWrapper.notIn(fieldName, fieldValue);
							break;
						case IN_STR:
							if (fieldValue instanceof String) {
								queryWrapper.in(fieldName, Arrays.asList(((String) fieldValue).split(",")));
							}
							break;
						case NOT_IN_STR:
							if (fieldValue instanceof String) {
								queryWrapper.notIn(fieldName, Arrays.asList(((String) fieldValue).split(",")));
							}
							break;
						case BETWEEN:
							List<Object> between = new ArrayList<>((List<Object>) fieldValue);
							queryWrapper.between(fieldName, between.get(0), between.get(1));
							break;
						case UNIX_TIMESTAMP:
							List<Object> UNIX_TIMESTAMP = new ArrayList<>((List<Object>) fieldValue);
							if (!UNIX_TIMESTAMP.isEmpty()) {
								SimpleDateFormat fm = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
								Date time1 = fm.parse(UNIX_TIMESTAMP.get(0).toString());
								Date time2 = fm.parse(UNIX_TIMESTAMP.get(1).toString());
								queryWrapper.between(fieldName, time1, time2);
							}
							break;
					}
				}

			}
		} catch (Exception e) {
			log.error(e.getMessage(), e);
		}
		return queryWrapper;
	}

	/**
	 * 获取包含排序的查询条件
	 *
	 * @return 包含排序的QueryWrapper
	 */
	public QueryWrapper<T> getOrderWrapper() {
		return getOrderWrapper(getWrapper());
	}

	/**
	 * 获取包含排序的查询条件
	 *
	 * @param queryWrapper 不含排序的QueryWrapper
	 * @return 包含排序的QueryWrapper
	 */
	public QueryWrapper<T> getOrderWrapper(QueryWrapper<T> queryWrapper) {
		if (queryWrapper == null) {
			queryWrapper = new QueryWrapper<>();
		}
		for (OrderItem orderItem : orders()) {
			if (orderItem.isAsc()) {
				queryWrapper.orderByAsc(orderItem.getColumn());
			} else {
				queryWrapper.orderByDesc(orderItem.getColumn());
			}
		}
		return queryWrapper;
	}

	/**
	 * 代码排序集合
	 *
	 * @param records 集合
	 * @return 排序后的集合
	 */
	public List<T> sortRecords(List<T> records) {
		List<OrderItem> orderItems = orders();
		if (records == null || records.size() < 2 || orderItems == null || orderItems.size() == 0) {
			return records;
		}
		Comparator<T> comparator = null;
		for (OrderItem item : orderItems) {
			if (item.getColumn() == null) {
				continue;
			}
			String field = this.isToUnderlineCase ? StrUtil.toCamelCase(item.getColumn()) : item.getColumn();
			Function keyExtractor = t -> ReflectUtil.getFieldValue(t, field);
			if (comparator == null) {
				if (item.isAsc()) {
					comparator = Comparator.comparing(keyExtractor);
				} else {
					comparator = Comparator.comparing(keyExtractor, Comparator.reverseOrder());
				}
			} else {
				if (item.isAsc()) {
					comparator.thenComparing(keyExtractor);
				} else {
					comparator.thenComparing(keyExtractor, Comparator.reverseOrder());
				}
			}
		}
		if (comparator != null) {
			return records.stream().sorted(comparator).collect(Collectors.toList());
		}
		return records;
	}

}
